<script lang="ts">
export default {
  name: 'Study5StuDemo4'
}
</script>

<template>
  <h2>watchEffect</h2>
  <div class="note">
    <h3>回调的触发时机</h3>
    <p>1. 默认情况下，侦听器回调会在父组件更新 (如有) 之后、所属组件的 DOM 更新之前被调用。</p>
    <p>2. 这意味着如果你尝试在侦听器回调中访问所属组件的 DOM，那么 DOM 将处于更新前的状态。</p>
    <p>3. 如果想在侦听器回调中能访问被 Vue 更新之后的所属组件的 DOM，你需要指明 flush: 'post' 选项：</p>
  </div>
  <div class="note">
    <h3>watchEffect</h3>
    <p>1. 可以监听一个ref对象（需要.value）</p>
    <p>2. 可以监听一个计算属性（需要.value）</p>
    <p>3. 可以直接监听一个ref的属性（不需要getter）</p>
    <p>4. 不能直接监听一个getter函数，需要自调用函数</p>
    <p>5. 监听多个数据源，对于有多个依赖项的侦听器来说，使用 watchEffect() 可以消除手动维护依赖列表的负担</p>
    <p>6. 监听多个数据源时，想要获取某个，可以使用解构</p>
  </div>
  <hr class="hr-style" />
  <div class="test">
    <div>inputVal: <input type="text" v-model="inputVal" /></div>
    <div>
      <label for="">num1:</label>
      <input type="number" v-model="num1" />
      <label for="">num2:</label>
      <input type="number" v-model="num2" />
      <div>求和：{{ sumNum }}</div>
    </div>
    <hr />
    <div>
      <input type="text" v-model="reacUser.name" />
      <input type="text" v-model="reacUser.sex" />
      <input type="text" v-model="reacUser.love.lanqiu" />
    </div>
  </div>

  <hr class="hr-style" />
  <div class="test">
    <div
      ref="my-input"
      style="width: 100px; height: 100px; background-color: skyblue"
      v-if="isShow"
    ></div>
    <button type="button" @click="changeShow">显示正方形</button>
  </div>
</template>

<script setup lang="ts">
import { computed, reactive, ref, useTemplateRef,watch, watchEffect } from 'vue'

const inputVal = ref('默认值')
const num1 = ref(0)
const num2 = ref(0)

const sumNum = computed(() => num1.value + num2.value)

const reacUser = reactive({
  name: '站起来',
  sex: '男',
  love: {
    lanqiu: '喜欢'
  }
})

const isShow = ref(false)
const inputDom = useTemplateRef('my-input')  // 用于获取input树
const changeShow = ()=>{
  isShow.value = true
}
// #回调的触发时机
// 默认情况下，侦听器回调会在父组件更新 (如有) 之后、所属组件的 DOM 更新之前被调用。
// 这意味着如果你尝试在侦听器回调中访问所属组件的 DOM，那么 DOM 将处于更新前的状态。
// 此处会打印两次，因为两个数据更新不同步：isShow更新一次获取值，inputDom更新一次获取值
watchEffect(()=>{
  console.log(isShow.value,"watchEffect:isShow.value");
  console.log(inputDom.value,"watchEffect:inputDom.value");
})
// flush:'post'可以使其同步更新
watchEffect(()=>{
  console.log(isShow.value,"watchEffect:isShow.value");
  console.log(inputDom.value,"watchEffect:inputDom.value");
},
{
  flush:'post'
})
watchEffect(()=>{
  console.log(isShow.value,"watchEffect:isShow.value");
})
watchEffect(()=>{
  console.log(inputDom.value,"watchEffect:inputDom.value");
})
watch(isShow,()=>{
  console.log(inputDom.value,'isShow:inputDom.value');
})
watch(inputDom,()=>{
  console.log(inputDom.value,'isShow:inputDom.value');
})

// 如果想在侦听器回调中能访问被 Vue 更新之后的所属组件的 DOM，你需要指明 flush: 'post' 选项：
watch(
  isShow,
  ()=>{
    console.log(inputDom.value,'isShow:inputDom.value');
  },
  {
    flush: 'post'
  }
)

// 1. 不能监听，只会在第一次返回一个ref
watchEffect(() => {
  console.log(inputVal, 'watchEffect:inputVal')
})

// 2. 可以直接监听一个ref对象（.value）
watchEffect(() => {
  console.log(inputVal.value, 'watchEffect:inputVal.value')
})
// 3. 可以直接监听一个计算属性（.value）
watchEffect(() => {
  console.log(sumNum.value, 'watchEffect:sumNum.value')
})
// 4. 可以直接监听一个ref的属性（不需要getter）
// 如果你需要侦听一个嵌套数据结构中的几个属性，watchEffect() 可能会比深度侦听器更有效，
// 因为它将只跟踪回调中被使用到的属性，而不是递归地跟踪所有的属性。
watchEffect(() => {
  console.log(reacUser.love.lanqiu, 'watchEffect:reacUser.love.lanqiu')
})

// 5. 不能直接监听一个getter函数，需要自调用函数
watchEffect(() => {
  console.log(() => num1.value * num2.value, 'watchEffect:() => num1.value * num2.value')
})
watchEffect(() => {
  console.log((() => num1.value * num2.value)(), 'watchEffect:(() => num1.value * num2.value)()')
})
// 6. 监听多个数据源
// 对于有多个依赖项的侦听器来说，使用 watchEffect() 可以消除手动维护依赖列表的负担
watchEffect(() => {
  console.log(
    [
      inputVal.value,
      (() => inputVal.value)(),
      (() => num1.value * num2.value)(),
      (() => num1.value + num2.value)()
    ],
    'inputVal.value,(() => inputVal.value)(),(() => num1.value * num2.value)(),(() => num1.value + num2.value)()'
  )
})
// if 想要获取单个数据，可以解构
watchEffect(() => {
  const [inputV, getInputVal, getSum, getMul] = [
    inputVal.value,
    (() => inputVal.value)(),
    (() => num1.value * num2.value)(),
    (() => num1.value + num2.value)()
  ]
  console.log(
    inputV,
    getInputVal,
    getSum,
    getMul,
    'inputVal.value,(() => inputVal.value)(),(() => num1.value * num2.value)(),(() => num1.value + num2.value)()'
  );
})
</script>

<style scoped>
body {
  padding: 20px;
}
h2 {
  color: red;
}
h3 {
  color: rgb(220, 85, 85);
}
h4 {
  color: skyblue;
}
.hr-style {
  border: 3px solid gold;
  margin: 20px 0;
}
.note {
  margin: 10px;
  padding: 10px;
  border: 3px solid rgb(221, 121, 202);
}
.note p {
  color: rgb(226, 106, 204);
  font-weight: bold;
}
</style>
